package com.jzo2o.health.handler;

import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.jzo2o.api.trade.RefundRecordApi;
import com.jzo2o.api.trade.dto.response.ExecutionResultResDTO;
import com.jzo2o.api.trade.enums.RefundStatusEnum;
import com.jzo2o.common.expcetions.BadRequestException;
import com.jzo2o.common.expcetions.DBException;
import com.jzo2o.common.model.CurrentUserInfo;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.health.mapper.OrdersCancelledMapper;
import com.jzo2o.health.mapper.OrdersMapper;
import com.jzo2o.health.mapper.OrdersRefundMapper;
import com.jzo2o.health.model.UserThreadLocal;
import com.jzo2o.health.model.domain.Orders;
import com.jzo2o.health.model.domain.OrdersCancelled;
import com.jzo2o.health.model.domain.OrdersRefund;
import com.jzo2o.health.model.domain.ReservationSetting;
import com.jzo2o.health.properties.OrdersJobProperties;
import com.jzo2o.health.service.IOrdersService;
import com.jzo2o.health.service.IReservationSettingService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.sl.usermodel.ObjectMetaData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 订单相关定时任务
 *
 * @author itcast
 * @create 2023/9/2 16:44
 **/
@Slf4j
@Component
public class OrdersHandler {

    @Autowired
    private RefundRecordApi refundRecordApi;
    @Autowired
    private OrdersJobProperties ordersJobProperties;

    @Autowired
    @Lazy
    private IOrdersService ordersService;

    /**
     * 支付超时取消订单
     * 每分钟执行一次
     */
    @XxlJob(value = "cancelOverTimePayOrder")
    public void cancelOverTimePayOrder() {
        List<Orders> list = ordersService.lambdaQuery()
                .le(Orders::getCreateTime, LocalDateTime.now().minusMinutes(15))
                .eq(Orders::getOrderStatus,0)
                .list();
        if(CollUtils.isEmpty(list)){
            return;
        }
        for (Orders orders : list) {
            ordersService.cancelOrdersByNoPay(orders,"超时未支付，系统自动取消",true);
        }
    }

    /**
     * 订单退款异步任务
     */
    @XxlJob(value = "handleRefundOrders")
    public void handleRefundOrders() {
        List<OrdersRefund> ordersRefunds = ordersRefundMapper.selectList(null);
        if(CollUtils.isEmpty(ordersRefunds)){
           return;
        }
        OrdersHandler owner = applicationContext.getBean(OrdersHandler.class);
        for (OrdersRefund ordersRefund : ordersRefunds) {
            owner.refundOrder(ordersRefund);
        }
    }

    /**
     * 订单退款处理
     */
    @Transactional(rollbackFor = Exception.class)
    public void refundOrder(OrdersRefund refund) {
        ExecutionResultResDTO executionResultResDTO=null;
        try {
            executionResultResDTO = refundRecordApi.refundTrading(refund.getTradingOrderNo(), refund.getRealPayAmount());
            //如果状态为退款中，则等待三秒，再调一次
            if(ObjectUtils.equals(executionResultResDTO.getRefundStatus(), RefundStatusEnum.SENDING.getCode())){
                TimeUnit.SECONDS.sleep(3);
                executionResultResDTO=refundRecordApi.refundTrading(refund.getTradingOrderNo(), refund.getRealPayAmount());
            }
        } catch (Exception e) {
            log.error("退款接口调用失败，退款信息为:{},失败原因为:{}",refund,e);
            throw new BadRequestException(e);
        }
        //判断executionResultResDTO是否为空
        if(ObjectUtils.isNull(executionResultResDTO)){
            log.error("退款接口调用失败，退款信息为:"+refund);
            throw new BadRequestException("退款接口调用失败，退款信息为:"+refund);
        }
        //判断退款状态是否为2
        if(!ObjectUtils.equals(executionResultResDTO.getRefundStatus(),RefundStatusEnum.SUCCESS.getCode())){
            log.error("退款接口调用失败，退款信息为:"+refund);
            throw new BadRequestException("退款接口调用失败，退款信息为:"+refund);
        }
        //修改订单信息
        boolean update = ordersService.lambdaUpdate()
                .set(Orders::getRefundId, executionResultResDTO.getRefundId())
                .set(Orders::getRefundNo, executionResultResDTO.getRefundNo())
                .set(Orders::getPayStatus, 3)
                .eq(Orders::getId, refund.getId())
                .update();
        if(!update){
            throw new DBException("退款，修改订单失败");
        }
        int i = ordersRefundMapper.deleteById(refund.getId());
        if(i==0){
            throw new DBException("退款，删除退款记录失败");
        }
        log.info("退款成功，退款信息:{},退款状态为:{}",refund,executionResultResDTO.getRefundStatus());
    }
    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private OrdersCancelledMapper ordersCancelledMapper;
    @Autowired
    private IReservationSettingService reservationSettingService;
    @Autowired
    private OrdersRefundMapper ordersRefundMapper;
    @Transactional(rollbackFor = Exception.class)
    @Async("taskExecutor")
    public void cancelOrderByDispatching(Orders orders, String cancelReason, CurrentUserInfo currentUserInfo) {
        OrdersCancelled cancelled = new OrdersCancelled();
        cancelled.setId(orders.getId());
        cancelled.setCancellerId(currentUserInfo.getId());//取消人id
        cancelled.setCancellerName(currentUserInfo.getName());//取消人name
        cancelled.setCancellerType(currentUserInfo.getUserType());
        cancelled.setCancelTime(LocalDateTime.now());
        cancelled.setCancelReason(cancelReason);//取消原因
        int insert = ordersCancelledMapper.insert(cancelled);
        if(insert==0){
            throw new DBException("取消记录添加失败");
        }
        boolean update = ordersService.lambdaUpdate()
                .set(Orders::getOrderStatus, 300)
                .eq(Orders::getId, orders.getId())
                .update();
        if(!update){
            throw new DBException("修改订单失败");
        }
        //添加退款记录
        OrdersRefund refund = new OrdersRefund();
        refund.setId(orders.getId());
        refund.setRealPayAmount(BigDecimal.valueOf(0.01));
        refund.setTradingOrderNo(orders.getTradingOrderNo());
        int insert1 = ordersRefundMapper.insert(refund);
        if(insert1==0){
            throw new DBException("添加退款记录失败");
        }

        boolean update1 = reservationSettingService.lambdaUpdate()
                .setSql("reservations=reservations-1")
                .eq(ReservationSetting::getOrderDate, orders.getReservationDate())
                .update();
        if(!update1){
            throw new DBException("更新预约表失败");
        }
// 申请退款
        OrdersHandler owner = applicationContext.getBean(OrdersHandler.class);
        owner.refundOrder(refund);
    }
}
